﻿/*
 * Created by SharpDevelop.
 * User: Masy Freddy
 * Date: 12/09/2011
 * Time: 17:16
 */
namespace ProviderTheTVDB
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Windows.Threading;
	using System.Xml.Linq;
	using System.Xml.Serialization;
	using System.Globalization;
	using MetaVideoEditorEvolved.AddIn.AddInViews;
	using MetaVideoEditorEvolved.AddIn.Entity;
	using MetaVideoEditorEvolved.Helper;

	[System.AddIn.AddIn("TheTvDb",
	                    Version = "1.0.0.0",
	                    Description = "Fournisseur d'accès de TheTvDb",
	                    Publisher = "Masy Freddy")]
	public class TheTVDBManager : ProviderView
	{
		public static readonly string TVDBApiKey = "B89CE93890E9419B",
		BannerUrl = "http://www.thetvdb.com/banners/",
		apiSearch = "http://www.thetvdb.com/api/GetSeries.php?language=all&seriesname={0}",
		apiGetInfo = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
		private ConfigurationAddIn configurationAddIn;
		
		public TheTVDBManager()
		{
			configurationAddIn = ConfigurationManager.Deserialize();
			
			if(configurationAddIn == null)
			{
				configurationAddIn = new ConfigurationAddIn()
				{
					Language = "fr",
					TraceLevel = "Error",
					SecondLanguage = 0
				};
				ConfigurationManager.Serialize(configurationAddIn);
			}
			
			Tracer.TracerInstance.Level= string.IsNullOrEmpty(configurationAddIn.TraceLevel) ? TracerLevel.Error : (TracerLevel)Enum.Parse(typeof(TracerLevel), configurationAddIn.TraceLevel);
			Tracer.TracerInstance.FileName = "TheTvDb";
		}
		
		public override List<MetaVideoEditorEvolved.AddIn.Entity.ProviderSearchResult> FindPossible(MetaVideoEditorEvolved.AddIn.Entity.ProviderSearchRequest request)
		{
			try
			{
				Tracer.TracerInstance.TraceInformation(string.Format("Start TheTvDB FindPossible (SearchName:{0}-Type{1})", request.Name, request.Type.ToString()));
				
				if(request.Type == MediaType.Serie)
				{
					Tracer.TracerInstance.TraceInformation(string.Format("Start to Download File Url:{0}",(string.Format(apiSearch, request.Name))));
					XDocument resultSerieWebRequest = DownloadManager.RetrieveXmlWebRequest(string.Format(apiSearch, request.Name));
					Tracer.TracerInstance.TraceInformation(string.Format("End to Download File Url:{0}",(string.Format(apiSearch, request.Name))));
					
					if(resultSerieWebRequest != null)
					{
						Tracer.TracerInstance.TraceInformation("Start to Deserialize");
						Data search = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
						Tracer.TracerInstance.TraceInformation("End Deserialize");
						
						if(search != null &&
						   search.Series != null)
						{
							Tracer.TracerInstance.TraceSuccessOperation(string.Format("End TheTvDb FindPossible (SearchName:{0}-Type{1})", request.Name, request.Type.ToString()));
							
							var result =  (from serie in search.Series
							               where serie.language == configurationAddIn.Language
							               select new ProviderSearchResult()
							               {
							               	Id = string.IsNullOrEmpty(serie.id) ? 0 : int.Parse(serie.id),
							               	Name = serie.SeriesName,
							               	Overview = serie.Overview,
							               	Picture = string.IsNullOrEmpty(serie.banner) ? null : new Uri(BannerUrl + serie.banner),
							               	Year = string.IsNullOrEmpty(serie.FirstAired) ? 0 : int.Parse(serie.FirstAired.Substring(0,4))
							               }).ToList();
							
							if(!result.Any() &&
							   configurationAddIn.SecondLanguage != LanguageName.None)
							{
								result =  (from serie in search.Series
								           where serie.language == configurationAddIn.SecondLanguage.ToString()
								           select new ProviderSearchResult()
								           {
								           	Id = string.IsNullOrEmpty(serie.id) ? 0 : int.Parse(serie.id),
								           	Name = serie.SeriesName,
								           	Overview = serie.Overview,
								           	Picture = string.IsNullOrEmpty(serie.banner) ? null : new Uri(BannerUrl + serie.banner),
								           	Year = string.IsNullOrEmpty(serie.FirstAired) ? 0 : int.Parse(serie.FirstAired.Substring(0,4))
								           }).ToList();
							}
							
							return result;
						}
					}
				}
				
				return new List<ProviderSearchResult>();
			}
			catch(Exception ex)
			{
				Tracer.TracerInstance.TraceError("Exception in TheTVDB provider FindPossible (SearchName:{0}-Type{1})", ex);
				throw new InvalidPluginException(Properties.Resources.UnknownError, ex);
			}
		}
		
		public override Serie FetchSerie(string serieId)
		{
			try
			{
				Tracer.TracerInstance.TraceInformation("Start TheTvDB FetchSerie Id:" + serieId);
				
				var xdocuments = DownloadManager.UnzipXmlDocument(string.Format(apiGetInfo, TVDBApiKey, serieId, configurationAddIn.Language), "TheTVDB" + serieId);
				
				if(xdocuments != null &&
				   xdocuments.Any())
				{
					XDocument resultSerieWebRequest = xdocuments.Where((l) => l.Key == configurationAddIn.Language + ".xml").First().Value;
					XDocument resultActorWebRequest = xdocuments.Where((l) => l.Key == "actors.xml").First().Value;
					XDocument resultBannerWebRequest = xdocuments.Where((l) => l.Key == "banners.xml").First().Value;
					
					Tracer.TracerInstance.TraceInformation("Start to Deserialize (General info)");
					Data searchSeries = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
					Tracer.TracerInstance.TraceInformation("End Deserialize (General info)");
					
					if((searchSeries == null || !searchSeries.Series.Any()) &&
					   configurationAddIn.SecondLanguage != LanguageName.None)
					{
						xdocuments = DownloadManager.UnzipXmlDocument(string.Format(apiGetInfo, TVDBApiKey, serieId, configurationAddIn.SecondLanguage.ToString()), "TheTVDB" + serieId);
						
						if(xdocuments != null &&
						   xdocuments.Any())
						{
							Tracer.TracerInstance.TraceInformation("Start the search with the second language");
							
							resultSerieWebRequest = xdocuments.Where((l) => l.Key == configurationAddIn.SecondLanguage.ToString() + ".xml").First().Value;
							resultActorWebRequest = xdocuments.Where((l) => l.Key == "actors.xml").First().Value;
							resultBannerWebRequest = xdocuments.Where((l) => l.Key == "banners.xml").First().Value;
							
							Tracer.TracerInstance.TraceInformation("Start to Deserialize (General info)");
							searchSeries = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
							Tracer.TracerInstance.TraceInformation("End Deserialize (General info)");
						}
					}
					
					if(searchSeries != null &&
					   searchSeries.Series.Any())
					{
						Tracer.TracerInstance.TraceInformation("Start to Deserialize (Banner and actor)");
						Actors searchActor = new XmlSerializer(typeof(Actors)).Deserialize(resultActorWebRequest.Root.CreateReader()) as Actors;
						Banners searchBanner = new XmlSerializer(typeof(Banners)).Deserialize(resultBannerWebRequest.Root.CreateReader()) as Banners;
						Tracer.TracerInstance.TraceInformation("End Deserialize (Banner and actor)");
						
						DataSeries searchSerie = searchSeries.Series.First();
						
						Serie serie = new Serie()
						{
							Backdrops = new List<Uri>(),
							CastMembers = new List<CastMember>(),
							Genres = new List<string>(),
							Graphicals = new List<Uri>(),
							Posters = new List<Uri>(),
							Studios = new List<string>()
						};
						
						serie.Duration = string.IsNullOrEmpty(searchSerie.Runtime) ? 0 : int.Parse(searchSerie.Runtime);
						serie.Id = searchSerie.id;
						serie.Name = searchSerie.SeriesName;
						serie.Overview = searchSerie.Overview;
						serie.Rating  = !string.IsNullOrEmpty(searchSerie.Rating) ? float.Parse(searchSerie.Rating, CultureInfo.InvariantCulture) : 0.0F;
						serie.Year = string.IsNullOrEmpty(searchSerie.FirstAired) ? 0  : int.Parse(searchSerie.FirstAired.Substring(0,4));
						
						if(!string.IsNullOrEmpty(searchSerie.Network))
						{
							serie.Studios.Add(searchSerie.Network);
						}
						
						if(searchActor.Actor != null)
						{
							serie.CastMembers = (from actor in searchActor.Actor
							                     select new CastMember()
							                     {
							                     	FullName = actor.Name,
							                     	Activity = "Actor",
							                     	Picture = string.IsNullOrEmpty(actor.Image) ? null : new Uri(BannerUrl + actor.Image),
							                     	Role = actor.Role
							                     }).ToList();
						}
						
						if(!string.IsNullOrEmpty(searchSerie.Genre))
						{
							serie.Genres = searchSerie.Genre.Trim('|').Split('|').ToList();
						}
						
						if(searchBanner.Banner != null &&
						   searchBanner.Banner.Any())
						{
							foreach (var banner in searchBanner.Banner) {
								switch (banner.BannerType) {
									case "fanart":
										serie.Backdrops.Add(new Uri(BannerUrl + banner.BannerPath));
										break;
									case "poster":
										serie.Posters.Add(new Uri(BannerUrl + banner.BannerPath));
										break;
									case "series":
										if(banner.BannerType2 == "graphical")
										{
											serie.Graphicals.Add(new Uri(BannerUrl + banner.BannerPath));
										}
										break;
								}
							}
						}
						
						Tracer.TracerInstance.TraceSuccessOperation("End TheTvDB FetchSerie Id:" + serieId);
						return serie;
					}
				}
				
				return null;
			}
			catch(Exception ex)
			{
				Tracer.TracerInstance.TraceError("End TheTvDB FetchSerie Id:" + serieId, ex);
				throw new InvalidPluginException(Properties.Resources.UnknownError, ex);
			}
		}
		
		public override Season FetchSeason(string serieId, int seasonNumber)
		{
			
			try
			{
				Tracer.TracerInstance.TraceInformation(string.Format("Fetch Season (Serie Id = {0}, Season Number = {1}", serieId, seasonNumber));
				
				var xdocuments = DownloadManager.UnzipXmlDocument(string.Format(apiGetInfo, TVDBApiKey, serieId, configurationAddIn.Language), "TheTVDB" + serieId);
				
				if(xdocuments != null &&
				   xdocuments.Any())
				{
					XDocument resultSerieWebRequest = xdocuments.Where((l) => l.Key == configurationAddIn.Language + ".xml").First().Value;
					XDocument resultBannerWebRequest = xdocuments.Where((l) => l.Key == "banners.xml").First().Value;
					
					Data searchSeries = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
					
					if(searchSeries == null)
					{
						xdocuments = DownloadManager.UnzipXmlDocument(string.Format(apiGetInfo, TVDBApiKey, serieId, configurationAddIn.SecondLanguage.ToString()), "TheTVDB" + serieId);
						
						if(xdocuments != null &&
						   xdocuments.Any())
						{
							resultSerieWebRequest = xdocuments.Where((l) => l.Key == configurationAddIn.SecondLanguage.ToString() + ".xml").First().Value;
							resultBannerWebRequest = xdocuments.Where((l) => l.Key == "banners.xml").First().Value;
							
							searchSeries = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
						}
					}
					
					if(searchSeries != null)
					{
						Banners searchBanner = new XmlSerializer(typeof(Banners)).Deserialize(resultBannerWebRequest.Root.CreateReader()) as Banners;

						var hasSeason = (from s in searchSeries.Episode
						                 where s.SeasonNumber == seasonNumber.ToString()
						                 select s).Any();
						
						if(hasSeason)
						{
							return new Season()
							{
								Number = seasonNumber,
								Images = (from b in searchBanner.Banner
								          where b.BannerType == "season" &&
								          b.Season == seasonNumber.ToString() &&
								          !string.IsNullOrEmpty(b.BannerPath)
								          select new Uri(BannerUrl + b.BannerPath)).ToList()
							};
						}
					}
				}
				
				return null;
			}
			catch(Exception ex)
			{
				Tracer.TracerInstance.TraceError(string.Format("Exception in TheTbDbManager FetchSeason SerieId={0} SeasonNumber={1}", serieId.ToString(), seasonNumber.ToString()), ex);
				throw new InvalidPluginException(Properties.Resources.UnknownError, ex);
			}
		}
		
		public override Episode FetchEpisode(string serieId, int seasonNumber, int episodeNumber)
		{
			try
			{
				Tracer.TracerInstance.TraceInformation(string.Format("FetchEpisode SerieId={0}, SeasonNumber={1}, EpisodeNumber={2}", serieId, seasonNumber, episodeNumber));
				var xdocuments = DownloadManager.UnzipXmlDocument(string.Format(apiGetInfo, TVDBApiKey, serieId, configurationAddIn.Language), "TheTVDB" + serieId);
				
				if(xdocuments != null &&
				   xdocuments.Any())
				{
					XDocument resultSerieWebRequest = xdocuments.Where((l) => l.Key == configurationAddIn.Language + ".xml").First().Value;
					XDocument resultBannerWebRequest = xdocuments.Where((l) => l.Key == "banners.xml").First().Value;
					
					Data searchSeries = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
					
					if(searchSeries == null)
					{
						xdocuments = DownloadManager.UnzipXmlDocument(string.Format(apiGetInfo, TVDBApiKey, serieId, configurationAddIn.SecondLanguage.ToString()), "TheTVDB" + serieId);
						
						if(xdocuments != null &&
						   xdocuments.Any())
						{
							resultSerieWebRequest = xdocuments.Where((l) => l.Key == configurationAddIn.SecondLanguage.ToString() + ".xml").First().Value;
							resultBannerWebRequest = xdocuments.Where((l) => l.Key == "banners.xml").First().Value;
							
							searchSeries = new XmlSerializer(typeof(Data)).Deserialize(resultSerieWebRequest.Root.CreateReader()) as Data;
						}
					}
					
					if(searchSeries != null)
					{
						Banners searchBanner = new XmlSerializer(typeof(Banners)).Deserialize(resultBannerWebRequest.Root.CreateReader()) as Banners;

						var hasEpisode = (from s in searchSeries.Episode
						                  where s.SeasonNumber == seasonNumber.ToString() &&
						                  s.EpisodeNumber == episodeNumber.ToString()
						                  select s).Any();
						
						if(hasEpisode)
						{
							var searchEpisode =  (from s in searchSeries.Episode
							                      where s.SeasonNumber == seasonNumber.ToString() &&
							                      s.EpisodeNumber == episodeNumber.ToString()
							                      select s).First();
							
							return new Episode()
							{
								Id = string.IsNullOrEmpty(searchEpisode.id) ? 0 : int.Parse(searchEpisode.id),
								Name = searchEpisode.EpisodeName,
								Number = string.IsNullOrEmpty(searchEpisode.EpisodeNumber) ? 0 : int.Parse(searchEpisode.EpisodeNumber),
								Overview = searchEpisode.Overview,
								Year = string.IsNullOrEmpty(searchEpisode.FirstAired) ? 0 : int.Parse(searchEpisode.FirstAired.Substring(0,4)),
								Rating = string.IsNullOrEmpty(searchEpisode.Rating) ? 0.0F : float.Parse(searchEpisode.Rating, CultureInfo.InvariantCulture),
								Directors = string.IsNullOrEmpty(searchEpisode.Director) ? new List<string>() : new List<string>(searchEpisode.Director.Trim('|').Split('|')),
								Writers = string.IsNullOrEmpty(searchEpisode.Writer) ? new List<string>() : new List<string>(searchEpisode.Writer.Trim('|').Split('|')),
								GuestStars =string.IsNullOrEmpty(searchEpisode.GuestStars) ? new List<string>() : new List<string>(searchEpisode.GuestStars.Trim('|').Split('|')),
								SeasonNumber = string.IsNullOrEmpty(searchEpisode.SeasonNumber) ? 0 : int.Parse(searchEpisode.SeasonNumber),
								FirstAired = searchEpisode.FirstAired,
								Images = string.IsNullOrEmpty (searchEpisode.filename) ? new List<Uri>() : new List<Uri>()
								{
									new Uri(BannerUrl + searchEpisode.filename)
								}
							};
						}
					}
				}
				
				return null;
			}
			catch(Exception ex)
			{
				Tracer.TracerInstance.TraceError(string.Format("Exception in TheTbDbManager FetchEpisode SerieId={0}, SeasonNumber={1}, EpisodeNumber={2}", serieId.ToString(), seasonNumber.ToString(), episodeNumber.ToString()), ex);
				throw new InvalidPluginException(Properties.Resources.UnknownError, ex);
			}
		}
		
		public override Movie FetchMovie(int movieId)
		{
			return null;
		}
		
		public override void ShowOption()
		{
			new Option(configurationAddIn).ShowDialog();
		}
		
		public override bool HasOption()
		{
			return true;
		}
	}
}